package com.pronosticnews.server.domain.dao.jpa;

import java.util.List;

import org.springframework.stereotype.Repository;

import com.pronosticnews.server.domain.dao.ParticipationDao;
import com.pronosticnews.server.domain.model.Club;
import com.pronosticnews.server.domain.model.Participation;
import com.pronosticnews.server.domain.model.Partie;
import com.pronosticnews.server.domain.model.Saison;

import fr.ysa.persistence.DaoException;
import fr.ysa.persistence.ImplJpaDao;
import fr.ysa.persistence.requetes.ConfigRequetes;
import fr.ysa.persistence.requetes.filtres.Filtre;
import fr.ysa.persistence.requetes.filtres.Filtre.TYPE;
import fr.ysa.persistence.requetes.filtres.ValueFiltre;
import fr.ysa.persistence.requetes.filtres.ValueFiltre.OPERATION;
import fr.ysa.services.ServiceException;

@Repository("participationDao")
public class ParticipationDaoJpa extends ImplJpaDao<Participation> implements
		ParticipationDao {

	public ParticipationDaoJpa() {
		setClazz(Participation.class);
	}

	@Override
	public void majClassement(Partie partie) throws ServiceException {
		// 1 - recup classement par club et saison pour les 2 equipes de la
		// partie
		Participation classementEquipeDomicile = getParticipation(
				partie.getEquipe1(), partie.getJournee().getSaison());
		Participation classementEquipeExterieur = getParticipation(
				partie.getEquipe2(), partie.getJournee().getSaison());

		// 2 - calcul les valeurs en fonction du resultat de la partie pour les
		// 2 equipes

		Integer matchsJouesDomicile = classementEquipeDomicile.getMatchsJoues();
		Integer matchsJouesExterieur = classementEquipeExterieur
				.getMatchsJoues();

		if (matchsJouesDomicile != null) {
			classementEquipeDomicile.setMatchsJoues(matchsJouesDomicile + 1);
		}

		if (matchsJouesExterieur != null) {
			classementEquipeExterieur.setMatchsJoues(matchsJouesExterieur + 1);
		}

		Integer butsEncaissesDomicile = classementEquipeDomicile
				.getButsEncaisses();
		Integer butsEncaissesExterieur = classementEquipeExterieur
				.getButsEncaisses();

		if (butsEncaissesExterieur != null && partie.getScoreEquipe2() != null) {
			classementEquipeDomicile.setButsEncaisses(butsEncaissesExterieur
					+ partie.getScoreEquipe2());
		}

		if (butsEncaissesDomicile != null && partie.getScoreEquipe1() != null) {
			classementEquipeExterieur.setButsEncaisses(butsEncaissesDomicile
					+ partie.getScoreEquipe1());
		}

		Integer butsMarquesDomicile = classementEquipeDomicile.getButsMarques();
		Integer butsMarquesExterieur = classementEquipeExterieur
				.getButsMarques();

		if (butsMarquesDomicile != null && partie.getScoreEquipe1() != null) {
			classementEquipeDomicile.setButsMarques(butsMarquesDomicile
					+ partie.getScoreEquipe1());
		}

		if (butsMarquesExterieur != null && partie.getScoreEquipe2() != null) {
			classementEquipeExterieur.setButsMarques(butsMarquesExterieur
					+ partie.getScoreEquipe2());
		}

		if (partie.getScoreEquipe1() != null
				&& partie.getScoreEquipe2() != null) {
			Integer pointsDomicile = classementEquipeDomicile.getPoints();
			Integer pointsExterieur = classementEquipeExterieur.getPoints();

			Integer gagnesDomicile = classementEquipeDomicile.getMatchsGagnes();
			Integer gagnesExterieur = classementEquipeExterieur
					.getMatchsGagnes();

			Integer perdusDomicile = classementEquipeDomicile.getMatchsPerdus();
			Integer perdusExterieur = classementEquipeExterieur
					.getMatchsPerdus();

			Integer nulDomicile = classementEquipeDomicile.getMatchsNuls();
			Integer nulExterieur = classementEquipeExterieur.getMatchsNuls();

			Integer diffButsDomicile = classementEquipeDomicile
					.getDifferenceButs();
			Integer diffButsExterieur = classementEquipeExterieur
					.getDifferenceButs();

			Integer diffButs = 0;

			if (partie.getScoreEquipe1() > partie.getScoreEquipe2()) {
				if (gagnesDomicile != null) {
					classementEquipeDomicile
							.setMatchsGagnes(gagnesDomicile + 1);
				}
				if (perdusExterieur != null) {
					classementEquipeExterieur
							.setMatchsPerdus(perdusExterieur + 1);
				}
				diffButs = partie.getScoreEquipe1() - partie.getScoreEquipe2();
				if (diffButsDomicile != null) {
					classementEquipeDomicile
							.setDifferenceButs(classementEquipeDomicile
									.getDifferenceButs() + diffButs);
				}
				if (diffButsExterieur != null) {
					classementEquipeExterieur
							.setDifferenceButs(classementEquipeExterieur
									.getDifferenceButs() - diffButs);
				}

				classementEquipeDomicile.setPoints(3);
				if (pointsDomicile != null) {
					classementEquipeDomicile.setPoints(pointsDomicile + 3);
				}

			} else if (partie.getScoreEquipe1() < partie.getScoreEquipe2()) {
				classementEquipeExterieur.setMatchsGagnes(1);
				classementEquipeDomicile.setMatchsPerdus(1);
				if (gagnesExterieur != null) {
					classementEquipeExterieur
							.setMatchsGagnes(gagnesExterieur + 1);
				}
				if (perdusDomicile != null) {
					classementEquipeDomicile
							.setMatchsPerdus(perdusDomicile + 1);
				}
				diffButs = partie.getScoreEquipe2() - partie.getScoreEquipe1();
				if (diffButsDomicile != null) {
					classementEquipeDomicile
							.setDifferenceButs(classementEquipeDomicile
									.getDifferenceButs() - diffButs);
				}
				if (diffButsExterieur != null) {
					classementEquipeExterieur
							.setDifferenceButs(classementEquipeExterieur
									.getDifferenceButs() + diffButs);
				}

				if (pointsExterieur != null) {
					classementEquipeExterieur.setPoints(pointsExterieur + 3);
				}

			} else {
				if (nulExterieur != null) {
					classementEquipeExterieur.setMatchsNuls(nulExterieur + 1);
				}
				if (nulDomicile != null) {
					classementEquipeDomicile.setMatchsNuls(nulDomicile + 1);
				}
				if (pointsDomicile != null) {
					classementEquipeDomicile.setPoints(pointsDomicile + 1);
					classementEquipeExterieur.setPoints(pointsExterieur + 1);
				}
			}
		}

		// 3 - met a jour les 2 classements
		try {
			if (classementEquipeDomicile.getId() != null) {

				modifier(classementEquipeDomicile);

			} else {
				sauvegarder(classementEquipeDomicile);
			}

			if (classementEquipeExterieur.getId() != null) {
				modifier(classementEquipeExterieur);
			} else {
				sauvegarder(classementEquipeExterieur);
			}
		} catch (DaoException e) {
			throw new ServiceException(e.getMessage());
		}

	}

	@Override
	public void majClassement(Partie partieAvant, Partie partieApres)
			throws ServiceException {

		if (partieAvant.getEquipe1() == null
				&& partieAvant.getEquipe2() == null) {
			majClassement(partieApres);
			return;
		}

		Participation classementEquipeDomicile = getParticipation(
				partieAvant.getEquipe1(), partieAvant.getJournee().getSaison());
		Participation classementEquipeExterieur = getParticipation(
				partieAvant.getEquipe2(), partieAvant.getJournee().getSaison());

		classementEquipeDomicile.setMatchsJoues(classementEquipeDomicile
				.getMatchsJoues() - 1);
		classementEquipeExterieur.setMatchsJoues(classementEquipeExterieur
				.getMatchsJoues() - 1);

		Integer butsEncaisses = classementEquipeDomicile.getButsEncaisses();
		if (butsEncaisses != null && partieAvant.getScoreEquipe2() != null) {
			classementEquipeDomicile.setButsEncaisses(butsEncaisses
					- partieAvant.getScoreEquipe2());
		}
		butsEncaisses = classementEquipeExterieur.getButsEncaisses();
		if (butsEncaisses != null && partieAvant.getScoreEquipe1() != null) {
			classementEquipeExterieur.setButsEncaisses(butsEncaisses
					- partieAvant.getScoreEquipe1());
		}

		Integer butsMarques = classementEquipeDomicile.getButsMarques();
		if (butsMarques != null && partieAvant.getScoreEquipe1() != null) {
			classementEquipeDomicile.setButsMarques(butsMarques
					- partieAvant.getScoreEquipe1());
		}
		butsMarques = classementEquipeExterieur.getButsMarques();
		if (butsMarques != null && partieAvant.getScoreEquipe2() != null) {
			classementEquipeExterieur.setButsMarques(butsMarques
					- partieAvant.getScoreEquipe2());
		}

		if (partieAvant.getScoreEquipe1() != null
				&& partieAvant.getScoreEquipe2() != null) {
			Integer pointsDomicile = classementEquipeDomicile.getPoints();
			Integer pointsExterieur = classementEquipeExterieur.getPoints();

			Integer gagnesDomicile = classementEquipeDomicile.getMatchsGagnes();
			Integer gagnesExterieur = classementEquipeExterieur
					.getMatchsGagnes();

			Integer perdusDomicile = classementEquipeDomicile.getMatchsPerdus();
			Integer perdusExterieur = classementEquipeExterieur
					.getMatchsPerdus();

			Integer nulDomicile = classementEquipeDomicile.getMatchsNuls();
			Integer nulExterieur = classementEquipeExterieur.getMatchsNuls();

			Integer diffButsDomicile = classementEquipeDomicile
					.getDifferenceButs();
			Integer diffButsExterieur = classementEquipeExterieur
					.getDifferenceButs();

			Integer diffButs = 0;

			if (partieAvant.getScoreEquipe1() > partieAvant.getScoreEquipe2()) {
				classementEquipeDomicile.setMatchsGagnes(gagnesDomicile - 1);
				classementEquipeExterieur.setMatchsPerdus(perdusExterieur - 1);

				diffButs = partieAvant.getScoreEquipe1()
						- partieAvant.getScoreEquipe2();

				if (diffButsDomicile != null) {
					classementEquipeDomicile
							.setDifferenceButs(classementEquipeDomicile
									.getDifferenceButs() - diffButs);
				}
				if (diffButsExterieur != null) {
					classementEquipeExterieur
							.setDifferenceButs(classementEquipeExterieur
									.getDifferenceButs() + diffButs);
				}

				classementEquipeDomicile.setPoints(pointsDomicile - 3);

			} else if (partieAvant.getScoreEquipe1() < partieAvant
					.getScoreEquipe2()) {
				if (gagnesExterieur != null) {
					classementEquipeExterieur
							.setMatchsGagnes(gagnesExterieur + 1);
				}
				if (perdusDomicile != null) {
					classementEquipeDomicile
							.setMatchsPerdus(perdusDomicile - 1);
				}

				diffButs = partieAvant.getScoreEquipe2()
						- partieAvant.getScoreEquipe1();

				if (diffButsDomicile != null) {
					classementEquipeDomicile
							.setDifferenceButs(classementEquipeDomicile
									.getDifferenceButs() + diffButs);
				}
				if (diffButsExterieur != null) {
					classementEquipeExterieur
							.setDifferenceButs(classementEquipeExterieur
									.getDifferenceButs() - diffButs);
				}

				if (pointsExterieur != null) {
					classementEquipeExterieur.setPoints(pointsExterieur - 3);
				}

			} else {
				if (nulExterieur != null) {
					classementEquipeExterieur.setMatchsNuls(nulExterieur - 1);
				}
				if (nulDomicile != null) {
					classementEquipeDomicile.setMatchsNuls(nulDomicile - 1);
				}

				if (pointsDomicile != null) {
					classementEquipeDomicile.setPoints(pointsDomicile - 1);
					classementEquipeExterieur.setPoints(pointsExterieur - 1);
				}

			}
		}
		try {
			modifier(classementEquipeDomicile);
			modifier(classementEquipeExterieur);
		} catch (DaoException e) {
			throw new ServiceException(e.getMessage());
		}
		majClassement(partieApres);
	}

	private Participation getParticipation(Club club, Saison saison)
			throws ServiceException {
		ConfigRequetes req = new ConfigRequetes();
		Filtre filtreClub = new Filtre();
		filtreClub.setName(Participation.VALUE_NAME.club.name());
		filtreClub.setType(TYPE.OBJECT);
		ValueFiltre valueClub = new ValueFiltre();
		valueClub.setOperation(OPERATION.EQUAL);
		filtreClub.getValues().add(valueClub);

		Filtre filtreSaison = new Filtre();
		filtreSaison.setName(Participation.VALUE_NAME.saison.name());
		filtreSaison.setType(TYPE.OBJECT);
		ValueFiltre valueSaison = new ValueFiltre();
		valueSaison.setOperation(OPERATION.EQUAL);
		filtreSaison.getValues().add(valueSaison);

		req.getFiltres().add(filtreClub);
		req.getFiltres().add(filtreSaison);

		Participation participation = null;

		try {
			valueClub.setValue(club.getId().toString());
			valueSaison.setValue(saison.getId().toString());
			List<Participation> participations = trouver(req);
			if (participations.size() == 0) {
				participation = new Participation();
				participation.setClub(club);
				participation.setSaison(saison);
			} else if (participations.size() == 1) {
				participation = participations.get(0);
			} else {
				throw new ServiceException();
			}

		} catch (DaoException e) {
			throw new ServiceException(e.getMessage());
		}
		return participation;
	}
}
